// 引入 reflect-metadata 库
import "reflect-metadata";
import {config} from "dotenv";
import express, {Request, Response} from "express";
import multer from "multer";
import {File} from "node:buffer";

const app = express();
app.use(express.json());
app.use(express.static(__dirname + "/public"));

// async function loaderUnMustModule() {
//     try {
//         // 尝试导入 express-ws 模块
//         const {default: MustModule} = await import("express-ws") as any;
//         return MustModule.default;
//     }
//     catch (error) {
//         console.warn("express-ws not found");
//         return null;
//     }
// }

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, "uploads/"); // 指定文件保存的目录
    },
    filename: function (req, file, cb) {
        cb(null, file.originalname); // 指定保存的文件名
    },
});

const upload = multer({storage: storage});

function getParamNames(func: Function): string[] {
    const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
    const ARGUMENT_NAMES = /([^\s,]+)/g;
    const fnStr = func.toString().replace(STRIP_COMMENTS, "");
    const result = fnStr
        .slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
        .match(ARGUMENT_NAMES);
    if (result === null) return [];
    return result.map((name) => name.trim());
}

interface BaseParamRelation {
    target: Object;
    methodName: string;
    paramIndex: number;
    paramName?: string,
    paramType?: any;
}

const baseParamRelationMap: Map<string, BaseParamRelation> = new Map();

/**
 * 拦截器容器，存储所有注册的拦截器，拦截path为key，HandlerInterceptor为值
 */
const interceptors : Map<string, HandlerInterceptor> = new Map();

interface HandlerInterceptor{
    /**
     * 请求前置处理
     * @param req 
     * @param res 
     * @param handler 
     */
    preHandle(req: Request, res: Response, handler: Object|object): boolean;

    /**
     * 请求后置处理
     * @param req 
     * @param res 
     * @param handler 
     */
    postHandle(req: Request, res: Response, handler: Object|object): void;

    /**
     * 请求完成处理
     * @param req 
     * @param res 
     * @param handler 
     */
    afterCompletion(req: Request, res: Response, handler: Object|object): void;
}

 class HandlerInterceptorExcuters{
    /**
     * 执行所有拦截器的preHandle方法
     * @param req 
     * @param res 
     * @param handler 
     */
 static excutePreHandle(req: Request, res: Response, handler: Object|object): boolean {
     for (const [key, interceptor] of interceptors) {
         if (!interceptor.preHandle(req, res, handler)) {
             return false;
         }
     }
     return true;

 }
    /**
     * 执行所有拦截器的postHandle方法
     * @param req 
     * @param res 
     * @param handler 
     */
    static excutePostHandle(req: Request, res: Response, handler: Object|object): void {
        for (const [key, interceptor] of interceptors) {
            interceptor.postHandle(req, res, handler);
        }
    }
    /**
     * 执行所有拦截器的afterCompletion方法
     * @param req 
     * @param res 
     * @param handler 
     */
    static excuteAfterCompletion(req: Request, res: Response, handler: Object|object): void {
        for (const [key, interceptor] of interceptors) {
            interceptor.afterCompletion(req, res, handler);
        }

    }
}

class HandlerInterceptorRegister{

    static registerInterceptor(path: string, interceptor: HandlerInterceptor): void {
        interceptors.set(path, interceptor);
    }
}

interface BaseMapping {
    // 请求方式
    method: string;
    // 目标方法
    tragetFunc: Function;
    // 目标对象
    targetObj: Object;
    // 请求uri
    path: string;
    // 是否是文件
    isFile?: boolean;
    // 是否是数组
    isArray?: boolean;
    // 是否是对象
    isObject?: boolean;
}

enum MappingType {
    GET = "GET",
    POST = "POST",
    PUT = "PUT",
    DELETE = "DELETE",
}

interface MappingStrategy {
    dispatch(baseMapping: BaseMapping): void;
}

abstract class BaseMappingStrategy implements MappingStrategy {

    abstract dispatch(baseMapping: BaseMapping): void;

    /**
     * 绑定方法参数名称与类型
     * @param baseMapping
     * @param paramNames
     */
    bindParamRelationMap(baseMapping:BaseMapping, paramNames: string[]): void {
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
         // 绑定方法参数名称与类型
         for (let i = 0; i < paramNames.length; i++) {
            const key =
                target.constructor.name + "_" + fnc.name + "_" + i;
            console.debug(
                target.constructor.name + "_" + fnc.name + "_" + i
            );
            let keyToParamNameMap: Map<string, string|undefined> = new Map();
            baseParamRelationMap.forEach(entry=>{
                // temKey: target.constructor.name + "_" + fnc.name + "_" + i
                const temKey = entry.target.constructor.name + "_" + entry.methodName + "_" + entry.paramIndex;
                // 如果key和temKey相同，则说明是同一个参数
                if(key === temKey){
                    // 如果key和temKey相同，则说明是同一个参数
                    keyToParamNameMap.set(key, entry.paramName);
                }
            })
            // map映射参数与对应类型
            baseParamRelationMap.set(key, {
                target: target,
                methodName: fnc.name,
                paramIndex: i,
                paramName: keyToParamNameMap.get(key)??paramNames[i],
                paramType: Reflect.getMetadata(
                    "design:paramtypes",
                    target,
                    fnc.name
                )[i],
            });
        }
    }

    /**
     * 获取具体名称的参数值
     * @param baseMapping 
     * @param paramNames 
     * @param reqParam 
     * @param params 
     */
    handleAliasParams(baseMapping:BaseMapping, paramNames: string[],reqParam: Record<string, any>, params: any[]): void {
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
        for (let i = 0; i < paramNames.length; i++) {
            if (baseParamRelationMap.has(
                target.constructor.name + "_" + fnc.name + "_" + i
            )) {
                const baseParamRelation = baseParamRelationMap.get(
                    target.constructor.name + "_" + fnc.name + "_" + i
                );
                if (baseParamRelation) {
                    // 明确类型断言，避免隐式 any
                    const paramName = baseParamRelation.paramName ?? paramNames[i];
                    if (reqParam[paramName] !== undefined) {
                        params.push(reqParam[paramName]);
                    } else {
                        params.push(undefined); // 处理未定义的情况
                    }
                }
            } else {
                const paramName = paramNames[i];
                if (reqParam[paramName] !== undefined) {
                    params.push(reqParam[paramName]);
                } else {
                    params.push(undefined); // 处理未定义的情况
                }
            }
        }
    }
}

class GetMappingStrategy extends BaseMappingStrategy {
    dispatch(baseMapping: BaseMapping): void {
        const path = baseMapping.path;
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
        //获取fnc函数的参数名称列表
        const paramNames = getParamNames(fnc);
        // 绑定方法参数名称与类型
        this.bindParamRelationMap(baseMapping, paramNames);
        app.get(path, (req: Request, res: Response) => {
            HandlerInterceptorExcuters.excutePreHandle(req, res, target);
            try {
                const reqParam: Record<string, any> = {...req.params, ...req.query};
                let params: any[] = [];
                this.handleAliasParams(baseMapping, paramNames, reqParam, params);
                const result = fnc.call(target, ...params, res);
                if (typeof result === "string") {
                    if (result.startsWith("file:")) {
                        console.debug(result);
                        res.download(
                            result.substring(result.indexOf(":") + 1),
                            function (err) {
                                if (err) {
                                    // 文件下载失败的处理逻辑
                                    res.status(404).send("文件不存在");
                                }
                            }
                        );
                        return;
                    } else if (result.startsWith("redirect:")) {
                        console.debug(result);
                        res.redirect(result.substring(result.indexOf(":") + 1));
                        return;
                    } else if (result.startsWith("json:")) {
                        console.debug(result);
                        res.json(result.substring(result.indexOf(":") + 1));
                        return;
                    } else if (result.startsWith("html:")) {
                        console.debug(result);
                        res.send(result.substring(result.indexOf(":") + 1));
                        return;
                    }
                }
                HandlerInterceptorExcuters.excutePostHandle(req, res, target);
                res.status(200).send(result);
            } catch (error) {
                console.error();
                if (error instanceof Error) {
                    res.status(500).send(error.message);
                }
                res.status(500).send(error);
            } finally {
                HandlerInterceptorExcuters.excuteAfterCompletion(req, res, target);
            }
        });
    }
}

class DeleteMappingStrategy extends BaseMappingStrategy {
    dispatch(baseMapping: BaseMapping): void {
        const path = baseMapping.path;
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
        //获取fnc函数的参数名称列表
        const paramNames = getParamNames(fnc);
        app.delete(path, (req: Request, res: Response) => {
            try {
                const reqParam = {...req.params, ...req.query};
                let params = [];
                for (let i = 0; i < paramNames.length; i++) {
                    params.push(reqParam[paramNames[i]]);
                }
                const result = fnc.call(target, ...params, res);
                res.status(200).send(result);
            } catch (error) {
                console.error();
                if (error instanceof Error) {
                    res.status(500).send(error.message);
                }
                res.status(500).send(error);
            }
        });
    }
}

class PostMappingStrategy extends BaseMappingStrategy {
    dispatch(baseMapping: BaseMapping): void {
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
        const key = baseMapping.tragetFunc.name;
        const isFile = baseMapping.isFile;
        const path = baseMapping.path;
        //获取fnc函数的参数名称列表
        const paramNames = getParamNames(fnc);
        // 获取fnc方法参数类型类别
        const paramTypes = Reflect.getMetadata("design:paramtypes", target, key);
        // map映射参数与对应类型
        const paramTypeMap = new Map();
        paramTypes.forEach((type: any, index: number) => {
            paramTypeMap.set(paramNames[index], type);
        });
        if (isFile) {
            app.post(path, upload.single("file"), (req: Request, res: Response) => {
                try {
                    const reqParam = {...req.params, ...req.query};
                    let params: any[] = [];
                    // 遍历paramTypeMap
                    paramTypeMap.forEach((type: any, name: string) => {
                        if (!reqParam[name] && type === File) {
                            //如果reqParam[name]存在，并且为数组类型
                            params.push(req.file);
                        }
                    });

                    const result = fnc.call(target, ...params, res);
                    res.status(200).send(result);
                } catch (error) {
                    console.error();
                    if (error instanceof Error) {
                        res.status(500).send(error.message);
                    }
                    res.status(500).send(error);
                }
            });
            return;
        }
        app.post(path, (req: Request, res: Response) => {
            try {
                const reqParam = {...req.params, ...req.query};
                let params: any[] = [];
                // 遍历paramTypeMap
                paramTypeMap.forEach((type: any, name: string) => {
                    //如果reqParam[name]存在，并且为基本数据类型
                    if (
                        reqParam[name] &&
                        (type === String ||
                            type === Number ||
                            type === Boolean ||
                            type === Date)
                    ) {
                        params.push(reqParam[name]);
                    } else if (!reqParam[name] && type === Array) {
                        //如果reqParam[name]存在，并且为数组类型
                        params.push(req.body);
                    } else if (!reqParam[name] && type === Object) {
                        //如果reqParam[name]存在，并且为对象类型
                        params.push(req.body);
                    }
                });

                const result = fnc.call(target, ...params, res);
                res.status(200).send(result);
            } catch (error) {
                console.error();
                if (error instanceof Error) {
                    res.status(500).send(error.message);
                }
                res.status(500).send(error);
            }
        });
        return;
    }
}

class PutMappingStrategy extends BaseMappingStrategy {
    dispatch(baseMapping: BaseMapping): void {
        const fnc: Function = baseMapping.tragetFunc;
        const target = baseMapping.targetObj;
        const key = baseMapping.tragetFunc.name;
        const path = baseMapping.path;
        //获取fnc函数的参数名称列表
        const paramNames = getParamNames(fnc);
        // 获取fnc方法参数类型类别
        const paramTypes = Reflect.getMetadata("design:paramtypes", target, key);
        // map映射参数与对应类型
        const paramTypeMap = new Map();
        paramTypes.forEach((type: any, index: number) => {
            paramTypeMap.set(paramNames[index], type);
        });
        app.put(path, (req: Request, res: Response) => {
            try {
                const reqParam = {...req.params, ...req.query};
                let params: any[] = [];
                // 遍历paramTypeMap
                paramTypeMap.forEach((type: any, name: string) => {
                    //如果reqParam[name]存在，并且为基本数据类型
                    if (
                        reqParam[name] &&
                        (type === String ||
                            type === Number ||
                            type === Boolean ||
                            type === Date)
                    ) {
                        params.push(reqParam[name]);
                    } else if (!reqParam[name] && type === Array) {
                        //如果reqParam[name]存在，并且为数组类型
                        params.push(req.body);
                    } else if (!reqParam[name] && type === Object) {
                        //如果reqParam[name]存在，并且为对象类型
                        params.push(req.body);
                    }
                });

                const result = fnc.call(target, ...params, res);
                res.status(200).send(result);
            } catch (error) {
                console.error();
                if (error instanceof Error) {
                    res.status(500).send(error.message);
                }
                res.status(500).send(error);
            }
        });
        return;
    }
}

let mappingStrategyMaps: Map<string, MappingStrategy> = new Map();
let baseUrlMappingMap: Map<string, BaseMapping> = new Map();
let decoratorPromises: Promise<void>[] = [];

//实现RestController类装饰器
const RestController = (path: string): ClassDecorator => {
    return (target: Function) => {
        // 类请求路径+方法请求路径适配
        baseUrlMappingMap.forEach((value, key) => {
            if (key.startsWith(target.name)) {
                value.path = path + value.path;
            }
        });
        console.log("RestController constructor");
        console.log("target-name:", target.name);
        decoratorPromises.push(Promise.resolve());
    };
};

// 实现RequestParam参数装饰器
const RequsetParam = (
    name: string = "",
    required: boolean = true,
    defaultValue: any = undefined
): ParameterDecorator => {
    return (
        target: Object,
        methodName: string | symbol | undefined,
        paramIndex: number
    ) => {
        // 类名+方法名称+参数索引
        const key =
            target.constructor.name + "_" + methodName?.toString() + "_" + paramIndex;
        const baseParamRelation: BaseParamRelation = {
            target: target,
            methodName: methodName?.toString() || "",
            paramIndex: paramIndex,
            paramName: name,
        };
        baseParamRelationMap.set(key, baseParamRelation);
        decoratorPromises.push(Promise.resolve());
    };
};

//PathVariable复用RequestParam
const PathVariable = (
    name: string = "",
    required: boolean = true,
    defaultValue: any = undefined
): ParameterDecorator => {
    return RequsetParam(name, required, defaultValue)
}

//使用express接收请求实现装饰器GetMapping
const GetMapping = (path: string): MethodDecorator => {
    return (
        target: Object,
        key: string | symbol,
        descriptor: PropertyDescriptor
    ) => {
        console.log(111111);
        const baseMapping: BaseMapping = {
            method: MappingType.GET,
            tragetFunc: descriptor.value,
            targetObj: target,
            path: path,
            isFile: false,
        };
        baseUrlMappingMap.set(
            // 类名+方法名
            target.constructor.name + "_" + descriptor.value.name,
            baseMapping
        );
        decoratorPromises.push(Promise.resolve());
    };
};

const DeleteMapping = (path: string): MethodDecorator => {
    return (
        target: Object,
        key: string | symbol,
        descriptor: PropertyDescriptor
    ) => {
        console.log("DELETEMAPPING");
        const baseMapping: BaseMapping = {
            method: MappingType.DELETE,
            tragetFunc: descriptor.value,
            targetObj: target,
            path: path,
        };
        baseUrlMappingMap.set(
            target.constructor.name + "_" + descriptor.value.name,
            baseMapping
        );
        decoratorPromises.push(Promise.resolve());
    };
};

const PostMapping = (
    path: string = "/",
    isFile: boolean = false
): MethodDecorator => {
    return (
        target: Object,
        key: string | symbol,
        descriptor: PropertyDescriptor
    ) => {
        console.log(22222);
        const baseMapping: BaseMapping = {
            method: MappingType.POST,
            tragetFunc: descriptor.value,
            targetObj: target,
            path: path,
            isFile: isFile,
        };
        baseUrlMappingMap.set(
            target.constructor.name + "_" + descriptor.value.name,
            baseMapping
        );
        decoratorPromises.push(Promise.resolve());
    };
};

const PutMapping = (path: string = "/"): MethodDecorator => {
    return (
        target: Object,
        key: string | symbol,
        descriptor: PropertyDescriptor
    ) => {
        console.log("PUTMAPPING");
        const baseMapping: BaseMapping = {
            method: MappingType.PUT,
            tragetFunc: descriptor.value,
            targetObj: target,
            path: path,
        };
        baseUrlMappingMap.set(
            target.constructor.name + "_" + descriptor.value.name,
            baseMapping
        );
        decoratorPromises.push(Promise.resolve());
    };
};

function init() {
    console.log("baseUrlMappingMap:", baseUrlMappingMap);
    mappingStrategyMaps.set(MappingType.GET, new GetMappingStrategy());
    mappingStrategyMaps.set(MappingType.POST, new PostMappingStrategy());
    mappingStrategyMaps.set(MappingType.PUT, new PutMappingStrategy());
    mappingStrategyMaps.set(MappingType.DELETE, new DeleteMappingStrategy());
    baseUrlMappingMap.forEach((value, key) => {
        console.debug("key:", key);
        // 调用 dispatch 方法
        mappingStrategyMaps.get(value.method)?.dispatch(value);
    });
}

// 确保所有装饰器执行完毕后再调用 init 函数
async function initAfterDecorators() {
    await Promise.all(decoratorPromises);
    init();
}

// 在适当的地方调用 initAfterDecorators
// initAfterDecorators()
function serverConfig(options?: { settingPath?: string }) {
    return config({
        path: options?.settingPath ? options.settingPath : ".env.development",
    });
}

async function startServer(port?: number, settingPath?: string) {
    await serverConfig({settingPath});
    await initAfterDecorators();
    const PORT = port || process.env.PORT || 3000;
    app.listen(PORT, () => {
        console.log(`Server is running on port ${PORT}`);
    });
}

// startServer();

export {
    app,
    initAfterDecorators,
    startServer,
    serverConfig,
    Request,
    Response,
    RestController,
    RequsetParam,
    PathVariable,
    GetMapping,
    PostMapping,
    DeleteMapping,
    PutMapping,
};
